/*
 ************************************************************************************************
 *                                                                                              *
 *  OSA cooperative RTOS for Microchip PIC-controllers: PIC10/12/16/18/24/dsPIC                 *
 *                                                                                              *
 *  URL:            http://wiki.pic24.ru/doku.php/en/osa/ref/intro                              *
 *                  http://picosa.narod.ru                                                      *
 *                                                                                              *
 *----------------------------------------------------------------------------------------------*
 *                                                                                              *
 *  File:           osa_picc18.h                                                                *
 *                                                                                              *
 *  Compilers:      HT-PICC STD                                                                 *
 *                  HT-PICC18 STD                                                               *
 *                  Microchip C18                                                               *
 *                  Microchip C30                                                               *
 *                                                                                              *
 *  Programmer:     Timofeev Victor                                                             *
 *                  osa@pic24.ru, testerplus@mail.ru                                            *
 *                                                                                              *
 *  Description:    PICC18 specific definitions                                                 *
 *                                                                                              *
 *                                                                                              *
 ************************************************************************************************
 */


#ifndef __OSAPICC18_H__
#define __OSAPICC18_H__





/************************************************************************************************
 *                                                                                              *
 *     Registers definitions                                                                    *
 *                                                                                              *
 ************************************************************************************************/

static volatile near unsigned int _fsr @ 0xFE9;
static volatile near char         _indf @ 0xFEF;
static volatile near char         _postinc @ 0xFEE;
static volatile near char         _postdec @ 0xFED;
static volatile near char         _preinc @ 0xFEC;

static volatile near unsigned char _fsr1l @ 0xFE1;

static volatile near char         _pcl @ 0xFF9;
static volatile near char         _pclath @ 0xFFA;
static volatile near char         _pclatu @ 0xFFB;
static volatile near char         _status @ 0xFD8;
static volatile near char         _tosl @ 0xFFD;
static volatile near char         _tosh @ 0xFFE;
static volatile near char         _tosu @ 0xFFF;
static volatile near char         _bsr @ 0xFE0;
static volatile near char         _wreg @ 0xFE8;
static volatile near char         _intcon @ 0xFF2;
static volatile near char         _rcon   @ 0xFD0;


static          near bit    _giel       @ ((unsigned)&_intcon*8)+6;
static          near bit    _gie        @ ((unsigned)&_intcon*8)+7;
static          near bit    _ipen       @ ((unsigned)&_rcon*8)+7;
static volatile near bit    _carry      @ ((unsigned)&_status*8)+0;


/************************************************************************************************
 *                                                                                              *
 *     Constants and types                                                                      *
 *                                                                                              *
 ************************************************************************************************/

#undef OS_SMSG_SIZE
#define OS_SMSG_SIZE    sizeof(OS_SMSG_TYPE)

//------------------------------------------------------------------------------

typedef unsigned int                _FSR_TYPE;

//------------------------------------------------------------------------------

#if defined(_ROMSIZE) && (_ROMSIZE <= 0x10000)

    typedef unsigned int                OST_CODE_POINTER;
    #define OS_CODE_POINTER_SIZE        2

#else

    typedef unsigned long               OST_CODE_POINTER;
    #define OS_CODE_POINTER_SIZE        4

#endif



//------------------------------------------------------------------------------




/************************************************************************************************
 *                                                                                              *
 *     Platform macros                                                                          *
 *                                                                                              *
 ************************************************************************************************/

#define _PIC18_POP()            asm("      pop     ");

#if defined(_ROMSIZE) && (_ROMSIZE <= 0x4000)
#define _PIC18_ERRATA_NOP()
#else
#define _PIC18_ERRATA_NOP()     asm("\t    dw 0xFFFF     ")
#endif


#define OS_CLRWDT()             asm(" clrwdt ");
#define OS_ClrWdt()             asm(" clrwdt ");
#define OS_SLEEP()              asm(" sleep  ");
#define OS_Sleep()              asm(" sleep  ");










/************************************************************************************************
 *                                                                                              *
 *     Context switching macros                                                                 *
 *                                                                                              *
 ************************************************************************************************/


//------------------------------------------------------------------------------
// Save/restore PC macros
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
#if OS_CODE_POINTER_SIZE == 2
//------------------------------------------------------------------------------

    #define _OS_SetPC()     asm("   movf    __postinc, w, c     ");         \
                            asm("   movff   __postinc, __pclath ");         \
                            asm("   movwf   __pcl, c            ");


    #define _OS_SavePC()    asm("   movff   __tosl, __preinc    ");         \
                            asm("   movff   __tosh, __preinc    ");

//------------------------------------------------------------------------------
#else
//------------------------------------------------------------------------------

    #define _OS_SetPC()     asm("   movf    __postinc, w, c     ");         \
                            asm("   movff   __postinc, __pclath ");         \
                            asm("   movff   __postinc, __pclatu ");         \
                            asm("   movwf   __pcl, c            ");


    #define _OS_SavePC()    asm("   movff   __tosl, __preinc    ");         \
                            asm("   movff   __tosh, __preinc    ");         \
                            asm("   movff   __tosu, __preinc    ");

//------------------------------------------------------------------------------
#endif
//------------------------------------------------------------------------------



/*
 ********************************************************************************
 *                                                                              *
 *  _OS_JumpToTask()                                                            *
 *                                                                              *
 *------------------------------------------------------------------------------*
 *                                                                              *
 *  description:        jump indirectly from kernel (OS_Sched) into task        *
 *                                                                              *
 ********************************************************************************
 */

#define _OS_JumpToTask()                                                                        \
    {                                                                                           \
        asm("    bra     _OS_call_indirrect         ");                                         \
                                                                                                \
        asm("_OS_jump_indirrect:                    ");                                         \
                                                                                                \
        _OS_SET_FSR_CUR_TASK();                                                                 \
        *((near char*)&OS_state) = _postinc;                                                    \
        _OS_SetPC();                                                                            \
                                                                                                \
        asm("_OS_call_indirrect:                    ");                                         \
                                                                                                \
        asm("   rcall   _OS_jump_indirrect          ");                                         \
        _OS_SET_FSR_CUR_TASK();                                                                 \
        asm("   movlw   0xD7                        "); /*  except bReady and bCanContinue*/    \
        asm("   andwf   __indf, f, c                ");                                         \
        asm("   movlw   0x28                        "); /*  bReady and bCanContinue*/           \
        asm("   andwf   _OS_state, w, c             ");                                         \
        asm("   iorwf   __indf, f, c                ");                                         \
    }


#define _OS_SaveRetAddr()

#define _OS_if_Ready()          _OS_SET_FSR_CUR_TASK();     \
                                if (_OS_bTaskReady)






/************************************************************************************************
 *                                                                                              *
 *     Return from task to OS_Sched macros                                                      *
 *                                                                                              *
 ************************************************************************************************/


/*
 ********************************************************************************
 *                                                                              *
 *   Switch control routines:                                                   *
 *                                                                              *
 *    _OS_GetReturnPoint()                - exit from task and save context     *
 *                                                                              *
 *    _OS_ReturnNoSave()                  - exit withowt saving return address  *
 *                                                                              *
 *    _OS_CLEAR_READY()                   - exit with saving address and        *
 *                                          clearing bReady                     *
 *                                                                              *
 *    _OS_CLEAR_READY_SET_CANCONTINUE()   - exit without saving address and     *
 *                                          clearing bReady and bCanContinue    *
 *                                                                              *
 ********************************************************************************
 */


extern void OS_SchedRetPoint (void);
extern void OS_SchedRetPointNoSave (void);
extern void OS_ClearReady (void);
extern void OS_ClearReadySetCanContinue (void);

extern void  _OS_SET_FSR_CUR_TASK (void);


//------------------------------------------------------------------------------
#define _OS_GetReturnPoint()        {                                           \
                                        OS_SchedRetPoint();                     \
                                        _PIC18_ERRATA_NOP();                    \
                                    }                                           \

//------------------------------------------------------------------------------
#define _OS_CLEAR_READY()           {                                           \
                                        OS_ClearReady();                        \
                                        _PIC18_ERRATA_NOP();                    \
                                    }                                           \

//------------------------------------------------------------------------------
#define _OS_CLEAR_READY_SET_CANCONTINUE()                                       \
                                    {                                           \
                                        OS_ClearReadySetCanContinue();          \
                                        _PIC18_ERRATA_NOP();                    \
                                    }                                           \

//------------------------------------------------------------------------------
#define _OS_ReturnNoSave()          {                                           \
                                        asm(" global _OS_SchedRetPointNoSave"); \
                                        OS_SchedRetPointNoSave();               \
                                        _PIC18_ERRATA_NOP();                    \
                                    }                                           \

//------------------------------------------------------------------------------








//______________________________________________________________________________
/******************************************************************************************
 *
 * MACROS FOR OLD STYLE STATIC TIMERS WORK
 *
 ******************************************************************************************/


#define __OS_Timer8Work(TIMER_ID, L)                                                            \
    {                                                                                           \
        if ((OS_Timeouts[(TIMER_ID)>>3]&(1<<((TIMER_ID)&7))))                                   \
        {                                                                                       \
            asm("\t    global   _OS_Timers8   ");                                               \
            asm("\t    movlb    (_OS_Timers8 + (" #TIMER_ID")) >> 8 ");                         \
            asm("\t    incfsz   (_OS_Timers8 + (" #TIMER_ID")) & 0xFF, f    ");                 \
            asm("\t    bra      _TIMER_NEXT_8_"#TIMER_ID"_"#L"     ");                          \
             OS_Timeouts[(TIMER_ID)>>3]&=~(1<<((TIMER_ID)&7));                                  \
            asm("_TIMER_NEXT_8_"#TIMER_ID"_"#L": ");                                            \
        }                                                                                       \
    }


#define __OS_Timer16Work(TIMER_ID, L)                                                           \
    {                                                                                           \
        if ((OS_Timeouts[(TIMER_ID+_OS_TIMER16_POS)>>3]&(1<<((TIMER_ID+_OS_TIMER16_POS)&7))))   \
        {                                                                                       \
            asm("\t    global   _OS_Timers16  ");                                               \
            asm("\t    movlb    (_OS_Timers16 + (" #TIMER_ID"*2)) >> 8 ");                      \
            asm("\t    infsnz   (_OS_Timers16 + (" #TIMER_ID"*2)+0) & 0xFF, f    ");            \
            asm("\t    incfsz   (_OS_Timers16 + (" #TIMER_ID"*2)+1) & 0xFF, f    ");            \
            asm("\t    bra      _TIMER_NEXT_16_"#TIMER_ID"_"#L"     ");                         \
             OS_Timeouts[(TIMER_ID+_OS_TIMER16_POS)>>3]&=~(1<<((TIMER_ID+_OS_TIMER16_POS)&7));  \
            asm("_TIMER_NEXT_16_"#TIMER_ID"_"#L": ");                                           \
        }                                                                                       \
    }


#define __OS_Timer24Work(TIMER_ID, L)                                                           \
    {                                                                                           \
        if ((OS_Timeouts[(TIMER_ID+_OS_TIMER24_POS)>>3]&(1<<((TIMER_ID+_OS_TIMER24_POS)&7))))   \
        {                                                                                       \
            asm("\t    global   _OS_Timers24  ");                                               \
            asm("\t    movlb    (_OS_Timers24 + (" #TIMER_ID"*2)) >> 8 ");                      \
            asm("\t    infsnz   (_OS_Timers24 + (" #TIMER_ID"*2)+0) & 0xFF, f    ");            \
            asm("\t    incfsz   (_OS_Timers24 + (" #TIMER_ID"*2)+1) & 0xFF, f    ");            \
            asm("\t    bra      _TIMER_NEXT_24_"#TIMER_ID"_"#L"     ");                         \
             OS_Timeouts[(TIMER_ID+_OS_TIMER24_POS)>>3]&=~(1<<((TIMER_ID+_OS_TIMER24_POS)&7));  \
            asm("_TIMER_NEXT_24_"#TIMER_ID"_"#L": ");                                           \
        }                                                                                       \
    }


#define __OS_Timer32Work(TIMER_ID, L)                                                           \
    {                                                                                           \
        if ((OS_Timeouts[(TIMER_ID+_OS_TIMER32_POS)>>3]&(1<<((TIMER_ID+_OS_TIMER32_POS)&7))))   \
        {                                                                                       \
            asm("\t    global   _OS_Timers32  ");                                               \
            asm("\t    movlb    (_OS_Timers32 + (" #TIMER_ID"*4)) >> 8 ");                      \
            asm("\t    incf     (_OS_Timers32 + (" #TIMER_ID"*4)+0) & 0xFF, f    ");            \
            asm("\t    bnc      _TIMER_NEXT_32_"#TIMER_ID"_"#L"     ");                         \
            asm("\t    movlw    0     ");                                                       \
            asm("\t    addwfc   (_OS_Timers32 + (" #TIMER_ID"*4)+1) & 0xFF, f    ");            \
            asm("\t    addwfc   (_OS_Timers32 + (" #TIMER_ID"*4)+2) & 0xFF, f    ");            \
            asm("\t    addwfc   (_OS_Timers32 + (" #TIMER_ID"*4)+3) & 0xFF, f    ");            \
            asm("\t    bnc      _TIMER_NEXT_32_"#TIMER_ID"_"#L"     ");                         \
             OS_Timeouts[(TIMER_ID+_OS_TIMER32_POS)>>3]&=~(1<<((TIMER_ID+_OS_TIMER32_POS)&7));  \
            asm("_TIMER_NEXT_32_"#TIMER_ID"_"#L": ");                                           \
        }                                                                                       \
    }







//______________________________________________________________________________
/******************************************************************************************
 *
 * MACROS FOR WORK WITH TASK TIMERS
 *
 ******************************************************************************************/


//------------------------------------------------------------------------------
#if   OS_CODE_POINTER_SIZE == 2
//------------------------------------------------------------------------------

    #if     OS_TTIMER_SIZE == 1
        #define ASM_OST_TCB_SIZE_CONST      asm("   OST_TCB_SIZE    equ     5");
    #elif   OS_TTIMER_SIZE == 2
        #define ASM_OST_TCB_SIZE_CONST      asm("   OST_TCB_SIZE    equ     6");
    #elif   OS_TTIMER_SIZE == 4
        #define ASM_OST_TCB_SIZE_CONST      asm("   OST_TCB_SIZE    equ     8");
    #endif

//------------------------------------------------------------------------------
#elif OS_CODE_POINTER_SIZE == 4
//------------------------------------------------------------------------------

    #if     OS_TTIMER_SIZE == 1
        #define ASM_OST_TCB_SIZE_CONST      asm("   OST_TCB_SIZE    equ     7");
    #elif   OS_TTIMER_SIZE == 2
        #define ASM_OST_TCB_SIZE_CONST      asm("   OST_TCB_SIZE    equ     8");
    #elif   OS_TTIMER_SIZE == 4
        #define ASM_OST_TCB_SIZE_CONST      asm("   OST_TCB_SIZE    equ    10");
    #endif


//------------------------------------------------------------------------------
#endif
//------------------------------------------------------------------------------



//------------------------------------------------------------------------------
// Set BSR for work with task timers
#define     ASM_SET_BANK    asm(" movlb      high(_OS_TaskVars)");              \
                            asm("OS_STATE_DELAY_BIT    equ  4");                \





//------------------------------------------------------------------------------
// Expression compiles correctly in this case only:
//        asm("   movwf   ("#TASK_ID" +1 )* OST_TCB_SIZE + low(_OS_TaskVars) - 3 ");
//------------------------------------------------------------------------------
#if   OS_TTIMER_SIZE == 1
//------------------------------------------------------------------------------

#define __OS_TaskTimerWork(TASK_ID, L)                                                          \
    asm("   btfss   ("#TASK_ID" + 0)* OST_TCB_SIZE + low(_OS_TaskVars), OS_STATE_DELAY_BIT");   \
    asm("   bra     $ + 6");                                                                    \
    asm("   infsnz  ("#TASK_ID" + 1)* OST_TCB_SIZE + low(_OS_TaskVars) - 1     ");              \
    asm("   bcf     ("#TASK_ID" + 0)* OST_TCB_SIZE + low(_OS_TaskVars), OS_STATE_DELAY_BIT");


//------------------------------------------------------------------------------
#elif OS_TTIMER_SIZE == 2
//------------------------------------------------------------------------------

#define __OS_TaskTimerWork(TASK_ID, L)                                                          \
    asm("   btfsc   ("#TASK_ID" + 0)* OST_TCB_SIZE + low(_OS_TaskVars), OS_STATE_DELAY_BIT");   \
    asm("   incfsz  ("#TASK_ID" + 1)* OST_TCB_SIZE + low(_OS_TaskVars) - 2     ");              \
    asm("   bra     $ + 6");                                                                    \
    asm("   infsnz  ("#TASK_ID" + 1)* OST_TCB_SIZE + low(_OS_TaskVars) - 1     ");              \
    asm("   bcf     ("#TASK_ID" + 0)* OST_TCB_SIZE + low(_OS_TaskVars), OS_STATE_DELAY_BIT");


//------------------------------------------------------------------------------
#elif OS_TTIMER_SIZE == 4
//------------------------------------------------------------------------------

#define __OS_TaskTimerWork(TASK_ID, L)                                                          \
    asm("   btfsc   ("#TASK_ID" + 0)* OST_TCB_SIZE + low(_OS_TaskVars), OS_STATE_DELAY_BIT");   \
    asm("   incfsz  ("#TASK_ID" + 1)* OST_TCB_SIZE + low(_OS_TaskVars) - 4     ");              \
    asm("   bra     $ + 12");                                                                   \
    asm("   infsnz  ("#TASK_ID" + 1)* OST_TCB_SIZE + low(_OS_TaskVars) - 3     ");              \
    asm("   incfsz  ("#TASK_ID" + 1)* OST_TCB_SIZE + low(_OS_TaskVars) - 2     ");              \
    asm("   bra     $ + 6");                                                                    \
    asm("   infsnz  ("#TASK_ID" + 1)* OST_TCB_SIZE + low(_OS_TaskVars) - 1     ");              \
    asm("   bcf     ("#TASK_ID" + 0)* OST_TCB_SIZE + low(_OS_TaskVars), OS_STATE_DELAY_BIT");

//------------------------------------------------------------------------------
#else
//------------------------------------------------------------------------------

#define __OS_TaskTimerWork(TASK_ID, L)                  \
    {                                                   \
        if (OS_TaskVars[TASK_ID].State.bDelay)          \
        {                                               \
            if (!++OS_TaskVars[TASK_ID].Timer)          \
                OS_TaskVars[TASK_ID].State.bDelay = 0;  \
        }                                               \
    }

//------------------------------------------------------------------------------
#endif      // if sizeof(OST_TIMER)
//------------------------------------------------------------------------------

/******************************************************************************************/









/******************************************************************************************
 *
 *  WORK WITH DYNAMIC TIMERS
 *
 ******************************************************************************************/

#ifdef OS_ENABLE_DTIMERS


//------------------------------------------------------------------------------
#if   OS_DTIMER_SIZE == 1
//------------------------------------------------------------------------------

    #define OS_INC_DTIMER()                                                             \
        {                                                                               \
            asm("   movlw   3                   ");                                     \
            asm("   addwf   __fsr, f, c         ");  /* FSR0L can't overflow here */    \
            asm("   incf    __postdec, f, c     ");                                     \
            asm("   movf    __postdec, w, c     ");                                     \
            asm("   movf    __postdec, w, c     ");                                     \
            if (_carry) _OS_SetIndfTimerTimeout;                                        \
        }                                                                               \


//------------------------------------------------------------------------------
#elif OS_DTIMER_SIZE == 2
//------------------------------------------------------------------------------

    #define OS_INC_DTIMER()                                                             \
        {                                                                               \
            _OS_DTimers.Flags.bTimeout = 0;                                             \
            asm("   movlw   3                   ");                                     \
            asm("   addwf   __fsr, f, c         ");  /* FSR0L can't overflow here */    \
            asm("   movlw   0 ");                                                       \
            asm("   incf    __postinc, f, c     ");                                     \
            asm("   addwfc  __postdec, f, c     ");                                     \
            if (_carry) _OS_DTimers.Flags.bTimeout = 1;                                 \
            asm("   movlw   3                   ");                                     \
            asm("   subwf   __fsr, f, c         "); /* FSR0L can't overflow here */     \
            if (_OS_DTimers.Flags.bTimeout)                                             \
                _OS_SetIndfTimerTimeout;                                                \
        }                                                                               \

//------------------------------------------------------------------------------
#elif OS_DTIMER_SIZE == 4
//------------------------------------------------------------------------------

    #define OS_INC_DTIMER()                                                             \
        {                                                                               \
            _OS_DTimers.Flags.bTimeout = 0;                                             \
            asm("   movlw   3                   ");                                     \
            asm("   addwf   __fsr, f, c         ");  /* FSR0L can't overflow here */    \
            asm("   movlw   0                   ");                                     \
            asm("   incf    __postinc, f, c     ");                                     \
            asm("   addwfc  __postinc, f, c     ");                                     \
            asm("   addwfc  __postinc, f, c     ");                                     \
            asm("   addwfc  __postdec, f, c     ");                                     \
            if (_carry) _OS_DTimers.Flags.bTimeout = 1;                                 \
            asm("   movlw   5                   ");                                     \
            asm("   subwf   __fsr, f, c         "); /* FSR0L can't overflow here */     \
            if (_OS_DTimers.Flags.bTimeout)                                             \
                _OS_SetIndfTimerTimeout;                                                \
        }                                                                               \

//------------------------------------------------------------------------------
#endif
//------------------------------------------------------------------------------


#define __OS_DTimersWork()                              \
    {                                                   \
        _fsr = (_FSR_TYPE) &_OS_DTimers.Flags;          \
                                                        \
    REPEAT:                                             \
                                                        \
        if (_OS_CheckPostincTimerNextEnable)            \
        {                                               \
                                                        \
            /* Point FSR to next timer in list   */     \
                                                        \
            asm("   movf    __postinc, w, c        ");  \
            asm("   movff   __postdec, __fsr + 1   ");  \
            asm("   movwf   __fsr + 0, c            "); \
            if (!_OS_CheckIndfTimerRun) goto REPEAT;    \
            OS_INC_DTIMER();                            \
                                                        \
            goto REPEAT;                                \
        }                                               \
    }



//------------------------------------------------------------------------------
#endif  // OS_ENABLE_DTIMER
//------------------------------------------------------------------------------




/******************************************************************************************
 *
 *
 *
 ******************************************************************************************/





#endif















